This mini series about “Offline Web Applications” shows you how to build a web application that your users can use while they are offline. I will give a session about this topic at Herbstcampus 2012.

JQuery, document.ready

We start by including some JavaScript in the dictionary page. The submit button needs an ID. We will implement the functions “loadDictionaryContent” and “submitDictionaryEntry” in the file “dicitionary.js”.

dictionary.html

<head>
    <!-- ... -->
    <script src="jquery-1.8.0.min.js"></script>
    <script src="dictionary.js"></script>
		
    <script>
        $(document).ready(function() {
            loadDictionaryContent();
            $('#submitButton').click(function() {
                submitDictionaryEntry($('#addForm').serialize());
                return false;
            });
        });
    </script>
</head>
<body>
    <!-- ... -->
                     <input type="submit" value="Add" id="submitButton"/>
    <!-- ... -->
</body>

dictionary.js

The JavaScript file implements the two functions “loadDictionaryContent” and “submitDictionaryEntry”. These use AJAX to call the backend to load the dictionary content and to save new words.

loadDictionaryContent = function() {
    $.ajax({
        url:'api/listEntries'
    }).done(function(data) {
        $(wordsList).empty();
        
        var dataArray = JSON.parse(data);
        $.each(dataArray, function(index, value) {
            $(wordsList).append('<div class="left">' + value.german + '</div>');
            $(wordsList).append('<div class="right">' + value.austrian + '</div>');
            $(wordsList).append('<div class="clear"></div>');
        });
    });
};

submitDictionaryEntry = function(formContent) {
    $.ajax({
        url:'api/newEntry',
        type: 'GET',
        data: formContent
    }).done(function(data) {
        loadDictionaryContent();
    });
};

API

We have to create the two API endpoints “api/listEntries” and “api/newEntry” in the backend. I use wicket pages to implement them. In a real project you should probably use a REST library.

ListEntries.java

public class ListEntries extends Page {
    private static final long serialVersionUID = 1L;
    
    @Inject private DictionaryService dictionaryService;
    
    public ListEntries() {
    }
    
    @Override
    public void renderPage() {
        List<DictionaryWordEntity> entries = dictionaryService.listAllEntries();
        String entriesJson = new Gson().toJson(entries);
        
        PrintWriter w = new PrintWriter(getResponse().getOutputStream());
        w.println(entriesJson);
        w.close();
    }
}

NewEntry.java

public class NewEntry extends Page {
    private static final long serialVersionUID = 1L;
    
    @Inject private DictionaryService dictionaryService;

    public NewEntry(PageParameters params) {
        String german = params.get("german").toString("");
        String austrian = params.get("austrian").toString("");

        dictionaryService.addWord(german, austrian);
    }
    
    @Override
    public void renderPage() {
    }
}

DictionaryApplication.java

public class DictionaryApplication extends WebApplication {
    @Override
    protected void init() {
        //...
        mountPage("api/listEntries", ListEntries.class);
        mountPage("api/newEntry", NewEntry.class);
    }
}

Cache Manifest

We have to update the cache manifest to include the 2 new javascript files. We also have to add the 2 API endpoints to the “NETWORK” section so the browser knows to request them online. You might notice that the browser does not update any “CACHE”d resources when the cache manifest is unchanged. To be able to control when the browser updates these resources we add a “version” comment that we increment every time a resource has changed. You should increment this version automatically during your build or deployment process in a real project. For this example manually incrementing the version number is good enough.

offline.manifest

CACHE MANIFEST
# Offline cache manifest for the dictionary application
# version 1

CACHE:
dictionary.html
style.css
jquery-1.8.0.min.js
dictionary.js

NETWORK:
api/listEntries
api/newEntry

Coming up next...

And that’s it: The dictionary application works again! And it is still available offline. But it still does not work in offline mode. For this we need to load all data into an offline data base. Stay tuned for part 4 where we will finish the application and make everything available offline!